package org.ncibi.cytoscape.metscape.plugin;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.SwingConstants;

import org.ncibi.cytoscape.metscape.action.AboutAction;
import org.ncibi.cytoscape.metscape.action.AnimateAction;
import org.ncibi.cytoscape.metscape.action.BuildNetworkAction;
import org.ncibi.cytoscape.metscape.action.ConceptFilterAction;
import org.ncibi.cytoscape.metscape.action.PathwayFilterAction;
import org.ncibi.cytoscape.metscape.action.RegistrationAction;
import org.ncibi.cytoscape.metscape.action.SelectExperimentalDataAction;
import org.ncibi.cytoscape.metscape.action.ShowLegendAction;
import org.ncibi.cytoscape.metscape.task.GetVersionTask;
import org.ncibi.cytoscape.metscape.ui.MouseClickHandler;
import org.ncibi.cytoscape.metscape.ui.PopupNodeContextMenuListener;
import org.ncibi.metab.version.Version;
import org.ncibi.metab.version.VersionFactory;
import org.ncibi.metab.version.VersionUtils;

import cytoscape.CyNetwork;
import cytoscape.Cytoscape;
import cytoscape.plugin.CytoscapePlugin;
import cytoscape.view.CyNetworkView;
import cytoscape.view.cytopanels.CytoPanel;
import cytoscape.view.cytopanels.CytoPanelState;
import cytoscape.visual.CalculatorCatalog;
import ding.view.DGraphView;

public class MetScapePlugin extends CytoscapePlugin{
 
	private static boolean isSessionRestored = false;
	private static JMenu metscapeMenu = null;
	private static JMenuItem buildNetworkMenuItem = null;
	private static JMenuItem selectExperimentalDataMenuItem = null;
	private static JMenuItem animateMenuItem = null;
	private static JMenuItem showLegendMenuItem = null;
	private static JMenu filterMenu = null;
	private static JMenuItem pathwayFilterMenuItem = null;
	private static JMenuItem conceptFilterMenuItem = null;
	private static JMenuItem aboutMenuItem = null;
	private static JMenuItem regMenuItem = null;
	private static PluginData pluginData = null;
    private static Version serverVersion = null;
    private static Version clientVersion = VersionFactory.newClientVersion();
    private static GetVersionTask versionTask = new GetVersionTask();
    
	public MetScapePlugin()  {
		// create a new action to respond to menu activation
		JMenu pluginsMenu = Cytoscape.getDesktop().getCyMenus().getOperationsMenu();
		final CalculatorCatalog catalog = Cytoscape.getVisualMappingManager().getCalculatorCatalog();
		if (!pluginsMenu.isMenuComponent(metscapeMenu)) {
			metscapeMenu = new JMenu("MetScape");
			
			buildNetworkMenuItem = new JMenuItem(new BuildNetworkAction());
			metscapeMenu.add(buildNetworkMenuItem);
			
			selectExperimentalDataMenuItem = new JMenuItem(new SelectExperimentalDataAction());
			metscapeMenu.add(selectExperimentalDataMenuItem);
			
			animateMenuItem = new JMenuItem(new AnimateAction());
			metscapeMenu.add(animateMenuItem);
			
			showLegendMenuItem = new JMenuItem(new ShowLegendAction());
			metscapeMenu.add(showLegendMenuItem);
			
			filterMenu = new JMenu("Filter By");
			
			pathwayFilterMenuItem = new JMenuItem(new PathwayFilterAction());
			filterMenu.add(pathwayFilterMenuItem);
			
			conceptFilterMenuItem = new JMenuItem(new ConceptFilterAction());
			filterMenu.add(conceptFilterMenuItem);
			
			metscapeMenu.add(filterMenu);
			
			aboutMenuItem = new JMenuItem(new AboutAction());
			metscapeMenu.add(aboutMenuItem);
			
			regMenuItem = new JMenuItem(new RegistrationAction());
			if(!PluginRegistration.isPluginRegistered())
				metscapeMenu.add(regMenuItem);
			pluginsMenu.add(metscapeMenu);
		}
		
		Cytoscape.getSwingPropertyChangeSupport().addPropertyChangeListener(Cytoscape.NETWORK_DESTROYED,new PropertyChangeListener() {
			public void propertyChange(PropertyChangeEvent evt) {
				CyNetwork destroyed = Cytoscape.getNetwork((String)evt.getNewValue());
				if(catalog.getVisualStyle("MetScape:"+destroyed.getIdentifier()) != null)
					catalog.removeVisualStyle("MetScape:"+destroyed.getIdentifier());
			}
		});
		
		Cytoscape.getPropertyChangeSupport().addPropertyChangeListener(new PropertyChangeListener() {
			public void propertyChange(PropertyChangeEvent evt) {
				if(evt.getPropertyName() == Cytoscape.CYTOSCAPE_INITIALIZED || 
						(evt.getPropertyName() == Cytoscape.RESTORE_PLUGIN_STATE)
						&& pluginData != null) {
					CytoPanel cytoPanel =  Cytoscape.getDesktop().getCytoPanel(SwingConstants.EAST);
					int panelIndex = cytoPanel.indexOfComponent("Node/Edge Details");
					if(panelIndex != -1) {
						cytoPanel.remove(panelIndex);
						cytoPanel.setState(CytoPanelState.HIDE);
					}
					if(BuildNetworkAction.getPanel() != null && BuildNetworkAction.getPanel().getParent() != null) {
						BuildNetworkAction.getPanel().close();
					}
					BuildNetworkAction.setPanel(null);
					if(PathwayFilterAction.getPanel() != null && PathwayFilterAction.getPanel().getParent() != null) {
						PathwayFilterAction.getPanel().close();
					}
					PathwayFilterAction.setPanel(null);
					if(ConceptFilterAction.getPanel() != null && ConceptFilterAction.getPanel().getParent() != null) {
						ConceptFilterAction.getPanel().close();
					}
					ConceptFilterAction.setPanel(null);
					pluginData = null;
					if(evt.getPropertyName() == Cytoscape.CYTOSCAPE_INITIALIZED) {
						List<String> stylesToRemove = new ArrayList<String>();
						for(String vsName: catalog.getVisualStyleNames()) {
							if(vsName.startsWith("MetScape")) {
								stylesToRemove.add(vsName);
							}
						}
						for(String styleToRemove: stylesToRemove)
							catalog.removeVisualStyle(styleToRemove);
					}
				}
				else if(evt.getPropertyName() == Cytoscape.SESSION_LOADED && isSessionRestored) {
					if(pluginData.isBuildNetworkPanelOpen())
						BuildNetworkAction.exec();
					if(pluginData.isPathwayFilterPanelOpen())
						PathwayFilterAction.exec();
					if(pluginData.isConceptFilterPanelOpen())
						ConceptFilterAction.exec();
					isSessionRestored = false;
				}
			}
		});
	}
	
	public static boolean isInitialized() {
		return pluginData != null;
	}
	
	public static PluginData getPluginData() { 
		if(pluginData == null)
			pluginData = new PluginData();
		return pluginData; 
	}

	public static void fetchServerVersion(){
		if (serverVersion == null) {
			serverVersion = versionTask.getServerVersion();
		}
	}
	
	public static Version getServerVersion() {
		return serverVersion;
	}

	public static boolean isVersionCompatible() {
		return VersionUtils.isCompatible(clientVersion,serverVersion);
	}

	public static String getServerVersionString() {
		if (serverVersion == null)
			return "Server version is null";
		return serverVersion.toString();
	}
	
	public static String getPluginVersionString() {
		return clientVersion.toString();
	}


	public static String getCompatiblityMessage(){
		return VersionUtils.getCompatibilityMessage(clientVersion,serverVersion);
	}
	
	
	public static void removeRegistrationMenuItem() {
		metscapeMenu.remove(regMenuItem);
	}
	
	// override the following two methods to save state in session.
	/**
	 * DOCUMENT ME!
	 * 
	 * @param pStateFileList
	 *            DOCUMENT ME!
	 */
	public void restoreSessionState(List<File> pStateFileList) {
		isSessionRestored = true;
		if ((pStateFileList == null) || (pStateFileList.size() == 0)) {
			//No previous state to restore
			return;
		}
		
		try {
			File sessionFile = pStateFileList.get(0);
			FileInputStream fin = new FileInputStream(sessionFile);
			XMLDecoder decoder = new XMLDecoder(fin);
		    pluginData = ((PluginData) decoder.readObject());
		    decoder.close();
		    fin.close();
		    
		    for(CyNetworkView view: Cytoscape.getNetworkViewMap().values()) {
		    	((DGraphView) view).getCanvas().addMouseListener(new MouseClickHandler());
		    	view.addNodeContextMenuListener(new PopupNodeContextMenuListener());
		    }
		} catch (Exception ee) {
			ee.printStackTrace();
		}
	}

	/**
	 * DOCUMENT ME!
	 * 
	 * @param pFileList
	 *            DOCUMENT ME!
	 */
	public void saveSessionStateFiles(List<File> pFileList) {
		if(pluginData == null) return;
		
		String tmpDir = System.getProperty("java.io.tmpdir");
		File sessionFile = new File(tmpDir, "MetScape.xml");

		try {
			FileOutputStream fout = new FileOutputStream(sessionFile);
			XMLEncoder encoder = new XMLEncoder(fout);
			encoder.writeObject(pluginData);
			encoder.close();
			fout.close();
		} catch (Exception ex) {
			ex.printStackTrace();
		}

		pFileList.add(sessionFile);
	}
	

 }
